package model

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"context"
	"encoding/json"
	"fmt"
	"github.com/olekukonko/tablewriter"
	"github.com/simonvetter/modbus"
	"os"
	"runtime/debug"
	"sync"
	"time"
)

type ModbusTCPConfig struct {
	Mode               string `json:"mode"`                 // TCP模式, [client,server]
	IP                 string `json:"ip"`                   // IP
	Port               int    `json:"port"`                 // 端口
	MaxClients         int    `json:"max_clients"`          // 最大客户端数量
	MaxRequestQuantity int    `json:"max_request_quantity"` // 单次读写寄存器或线圈最大数量
	ConnectTimeout     int    `json:"connect_timeout"`      // 连接超时时间 (单位ms)
	ResponseTimeout    int    `json:"response_timeout"`     // 响应超时时间 (单位ms)
}

/*--- 下面为 Modbus Client ---*/
func modbus0x01(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x01 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x01线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			frameItem := make([]*FrameItemParam, 0)
			err := json.Unmarshal([]byte(frame.JsonDetail), &frameItem)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
				return
			}

			now := tools.GetNow()
			err = client.SetUnitId(frame.SlaveID)
			if err != nil {
				j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
				return
			}
			startAddr := frame.StartAddr
			quantity := uint16(frame.Quantity)
			frame.Length = int(quantity)
			buffer, err := client.ReadCoils(startAddr, quantity)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadCoils error %s\n", tools.GetNow(), err.Error()), frame.StartAddr, frame.Quantity})
				return
			}
			if len(buffer) != int(quantity) {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadCoils %s\n", tools.GetNow(), "返回结果不符合预期")})
				return
			}

			data := make([][]string, 0)
			/*--- 变量解析开始 ---*/
			messageList := make([]*QueueValue, 0)
			for _, item := range frameItem {
				var value float64
				if buffer[item.Start] == false {
					value = float64(0)
				} else {
					value = float64(1)
				}
				data = append(data, []string{
					item.Addr,
					item.FieldName,
					item.SpecType,
					fmt.Sprintf("%v", tools.FormatFloat(value)),
					fmt.Sprintf("%v", item.Start),
				})
				// 变量保存到 redis 队列
				queueData := QueueValue{}
				queueData.SpecType = item.SpecType
				queueData.Addr = item.Addr
				queueData.FieldName = item.FieldName
				queueData.Value = value
				queueData.CreateTime = &now
				messageList = append(messageList, &queueData)
			}
			if len(messageList) > 0 {
				go VariablesMap.PushMessageToClients(messageList)
			}
			/*--- 变量解析结束 ---*/
			if len(data) > 0 {
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 读取点位", ppe.Name, frame.Name)})
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"地址", "变量名", "类型", "解析值", "START"})
				for _, v := range data {
					table.Append(v)
				}
				table.Render()
			}
			time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
		}
	}
}
func modbus0x02(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x02 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x02线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			frameItem := make([]*FrameItemParam, 0)
			err := json.Unmarshal([]byte(frame.JsonDetail), &frameItem)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
				return
			}

			now := tools.GetNow()
			err = client.SetUnitId(frame.SlaveID)
			if err != nil {
				j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
				return
			}
			startAddr := frame.StartAddr
			quantity := uint16(frame.Quantity)
			frame.Length = int(quantity)
			buffer, err := client.ReadDiscreteInputs(startAddr, quantity)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadDiscreteInputs error %s\n", tools.GetNow(), err.Error()), frame.StartAddr, frame.Quantity})
				return
			}
			if len(buffer) != int(quantity) {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadDiscreteInputs %s\n", tools.GetNow(), "返回结果不符合预期")})
				return
			}

			data := make([][]string, 0)
			/*--- 变量解析开始 ---*/
			messageList := make([]*QueueValue, 0)
			for _, item := range frameItem {
				var value float64
				if buffer[item.Start] == false {
					value = float64(0)
				} else {
					value = float64(1)
				}
				data = append(data, []string{
					item.Addr,
					item.FieldName,
					item.SpecType,
					fmt.Sprintf("%v", tools.FormatFloat(value)),
					fmt.Sprintf("%v", item.Start),
				})
				// 变量保存到 redis 队列
				queueData := QueueValue{}
				queueData.SpecType = item.SpecType
				queueData.Addr = item.Addr
				queueData.FieldName = item.FieldName
				queueData.Value = value
				queueData.CreateTime = &now
				messageList = append(messageList, &queueData)
			}
			if len(messageList) > 0 {
				go VariablesMap.PushMessageToClients(messageList)
			}
			/*--- 变量解析结束 ---*/
			if len(data) > 0 {
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 读取点位", ppe.Name, frame.Name)})
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"地址", "变量名", "类型", "解析值", "START"})
				for _, v := range data {
					table.Append(v)
				}
				table.Render()
			}
			time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
		}
	}
}
func modbus0x03(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x03 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x03线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			frameItem := make([]*FrameItemParam, 0)
			err := json.Unmarshal([]byte(frame.JsonDetail), &frameItem)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
				return
			}

			now := tools.GetNow()
			err = client.SetUnitId(frame.SlaveID)
			if err != nil {
				j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
				return
			}
			startAddr := frame.StartAddr
			quantity := uint16(frame.Quantity)

			buffer, err := client.ReadBytes(startAddr, quantity*2, 0)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadBytes error %s\n", tools.GetNow(), err.Error()), frame.StartAddr, frame.Quantity})
				return
			}
			if len(buffer) != int(quantity*2) {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadBytes %s\n", tools.GetNow(), "返回结果不符合预期")})
				return
			}

			data := make([][]string, 0)
			/*--- 变量解析开始 ---*/
			messageList := make([]*QueueValue, 0)

			for _, item := range frameItem {
				var value float64
				var valueStr string
				switch item.SpecType {
				case "uint8":
					v := buffer[item.Start]
					value = float64(v)
				case "int8":
					v := buffer[item.Start]
					value = float64(int8(v))
				case "uint16":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 2)
					v := tools.BytesToUint16(rawBytes, item.Endian)
					value = float64(v)
				case "int16":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 2)
					v := tools.BytesToUint16(rawBytes, item.Endian)
					value = float64(int16(v))
				case "uint32":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 4)
					v := tools.BytesToUint32(rawBytes, item.Endian)
					value = float64(v)
				case "int32":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 4)
					v := tools.BytesToUint32(rawBytes, item.Endian)
					value = float64(int32(v))
				case "uint64":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 8)
					v := tools.BytesToUint64(rawBytes, item.Endian)
					value = float64(v)
				case "int64":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 8)
					v := tools.BytesToUint64(rawBytes, item.Endian)
					value = float64(int64(v))
				case "float32":
					//fmt.Printf("len=%d, start=%d, end=%d\n", len(buffer), item.Start, item.End+1)
					v := tools.BytesToFloat32(buffer[item.Start:item.End+1], item.Endian)
					value = float64(v)
				case "float64":
					v := tools.BytesToFloat64(buffer[item.Start:item.End+1], item.Endian)
					value = v
				case "bool":
					if buffer[item.Start] == 0 {
						value = float64(0)
					} else {
						value = float64(1)
					}
				}
				data = append(data, []string{
					item.Addr,
					item.FieldName,
					item.SpecType,
					tools.ByteArrayToHexStr(buffer[item.Start : item.End+1]),
					fmt.Sprintf("%v", tools.FormatFloat(value)),
					fmt.Sprintf("%v", item.Start),
					fmt.Sprintf("%v", item.End),
					fmt.Sprintf("%v", valueStr),
				})

				// 变量保存到 redis 队列
				queueData := QueueValue{}
				queueData.SpecType = item.SpecType
				queueData.Addr = item.Addr
				queueData.FieldName = item.FieldName
				queueData.Value = value
				queueData.CreateTime = &now
				messageList = append(messageList, &queueData)
			}

			if len(messageList) > 0 {
				go VariablesMap.PushMessageToClients(messageList)
			}
			/*--- 变量解析结束 ---*/
			if len(data) > 0 {
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 读取点位", ppe.Name, frame.Name)})
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"地址", "变量名", "类型", "原始数据", "解析值", "START", "END", "string"})
				for _, v := range data {
					table.Append(v)
				}
				table.Render()
			}
			time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
		}
	}
}
func modbus0x04(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x04 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x04线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			frameItem := make([]*FrameItemParam, 0)
			err := json.Unmarshal([]byte(frame.JsonDetail), &frameItem)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
				return
			}

			now := tools.GetNow()
			err = client.SetUnitId(frame.SlaveID)
			if err != nil {
				j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
				return
			}
			startAddr := frame.StartAddr
			quantity := uint16(frame.Quantity)

			buffer, err := client.ReadBytes(startAddr, quantity*2, 0)
			if err != nil {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadBytes error %s\n", tools.GetNow(), err.Error()), frame.StartAddr, frame.Quantity})
				return
			}
			if len(buffer) != int(quantity*2) {
				j_log.LogError([]interface{}{fmt.Sprintf("【%s】 ReadBytes %s\n", tools.GetNow(), "返回结果不符合预期")})
				return
			}

			data := make([][]string, 0)
			/*--- 变量解析开始 ---*/
			messageList := make([]*QueueValue, 0)

			for _, item := range frameItem {
				var value float64
				var valueStr string
				switch item.SpecType {
				case "uint8":
					v := buffer[item.Start]
					value = float64(v)
				case "int8":
					v := buffer[item.Start]
					value = float64(int8(v))
				case "uint16":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 2)
					v := tools.BytesToUint16(rawBytes, item.Endian)
					value = float64(v)
				case "int16":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 2)
					v := tools.BytesToUint16(rawBytes, item.Endian)
					value = float64(int16(v))
				case "uint32":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 4)
					v := tools.BytesToUint32(rawBytes, item.Endian)
					value = float64(v)
				case "int32":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 4)
					v := tools.BytesToUint32(rawBytes, item.Endian)
					value = float64(int32(v))
				case "uint64":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 8)
					v := tools.BytesToUint64(rawBytes, item.Endian)
					value = float64(v)
				case "int64":
					rawBytes := tools.BytesPaddingLeft(buffer[item.Start:item.End+1], 8)
					v := tools.BytesToUint64(rawBytes, item.Endian)
					value = float64(int64(v))
				case "float32":
					//fmt.Printf("len=%d, start=%d, end=%d\n", len(buffer), item.Start, item.End+1)
					v := tools.BytesToFloat32(buffer[item.Start:item.End+1], item.Endian)
					value = float64(v)
				case "float64":
					v := tools.BytesToFloat64(buffer[item.Start:item.End+1], item.Endian)
					value = v
				case "bool":
					if buffer[item.Start] == 0 {
						value = float64(0)
					} else {
						value = float64(1)
					}
				}
				data = append(data, []string{
					item.Addr,
					item.FieldName,
					item.SpecType,
					tools.ByteArrayToHexStr(buffer[item.Start : item.End+1]),
					fmt.Sprintf("%v", tools.FormatFloat(value)),
					fmt.Sprintf("%v", item.Start),
					fmt.Sprintf("%v", item.End),
					fmt.Sprintf("%v", valueStr),
				})

				// 变量保存到 redis 队列
				queueData := QueueValue{}
				queueData.SpecType = item.SpecType
				queueData.Addr = item.Addr
				queueData.FieldName = item.FieldName
				queueData.Value = value
				queueData.CreateTime = &now
				messageList = append(messageList, &queueData)
			}

			if len(messageList) > 0 {
				go VariablesMap.PushMessageToClients(messageList)
			}
			/*--- 变量解析结束 ---*/
			if len(data) > 0 {
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 读取点位", ppe.Name, frame.Name)})
				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"地址", "变量名", "类型", "原始数据", "解析值", "START", "END", "string"})
				for _, v := range data {
					table.Append(v)
				}
				table.Render()
			}
			time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
		}
	}
}
func modbus0x0F(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x0F panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x0F线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			if frame.SendType == 1 {
				list := make([]*FrameItemParam, 0)
				err := json.Unmarshal([]byte(frame.JsonDetail), &list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
					return
				}
				err = client.SetUnitId(frame.SlaveID)
				if err != nil {
					j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
					return
				}
				startAddr := frame.StartAddr
				data, err := CreateFrameCoilsRawData(list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
					return
				}
				if len(data) != frame.Quantity {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]写入的线圈个数与原始数据字节数不符;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
					return
				}
				err = client.WriteCoils(startAddr, data)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteCoils error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
					return
				}
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x0F写入线圈成功", ppe.Name, frame.Name)})
				time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
			} else {
				match, err := IsTriggerConditionMatched(frame)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s] frame_id=%d, IsTriggerConditionMatched error %s", frame.Name, frame.ID, err.Error())})
					return
				}
				if match {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧满足条件", frame.Name, frame.ID)})
					if time.Now().Sub(frame.LastTriggerTime).Seconds() < float64(frame.TriggerInterval) {
						j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧距离下一次触发时间间隔未到, 跳过", frame.Name, frame.ID)})
						time.Sleep(1000 * time.Millisecond)
						continue
					}

					list := make([]*FrameItemParam, 0)
					err := json.Unmarshal([]byte(frame.JsonDetail), &list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
						return
					}

					err = client.SetUnitId(frame.SlaveID)
					if err != nil {
						j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
						return
					}
					startAddr := frame.StartAddr
					data, err := CreateFrameCoilsRawData(list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
						return
					}
					if len(data) != frame.Quantity {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]写入的线圈个数与原始数据字节数不符;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
						return
					}
					err = client.WriteCoils(startAddr, data)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteCoils error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
						return
					}
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x0F写入线圈成功", ppe.Name, frame.Name)})

					frame.LastTriggerTime = time.Now()
				} else {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧不满足条件, 跳过", frame.Name, frame.ID)})
				}
				time.Sleep(1000 * time.Millisecond)
			}
		}
	}
}
func modbus0x10(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x10 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x10线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			if frame.SendType == 1 {
				list := make([]*FrameItemParam, 0)
				err := json.Unmarshal([]byte(frame.JsonDetail), &list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
					return
				}
				err = client.SetUnitId(frame.SlaveID)
				if err != nil {
					j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
					return
				}
				startAddr := frame.StartAddr
				data, err := CreateFrameRawData(list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
					return
				}
				if len(data) != frame.Quantity*2 {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]写入的寄存器个数与原始数据字节数不符;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
					return
				}
				err = client.WriteBytes(startAddr, data)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteBytes error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
					return
				}
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x10写入寄存器成功", ppe.Name, frame.Name)})
				time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
			} else {
				match, err := IsTriggerConditionMatched(frame)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s] frame_id=%d, IsTriggerConditionMatched error %s", frame.Name, frame.ID, err.Error())})
					return
				}
				if match {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧满足条件", frame.Name, frame.ID)})
					if time.Now().Sub(frame.LastTriggerTime).Seconds() < float64(frame.TriggerInterval) {
						j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧距离下一次触发时间间隔未到, 跳过", frame.Name, frame.ID)})
						time.Sleep(1000 * time.Millisecond)
						continue
					}

					list := make([]*FrameItemParam, 0)
					err := json.Unmarshal([]byte(frame.JsonDetail), &list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
						return
					}
					err = client.SetUnitId(frame.SlaveID)
					if err != nil {
						j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
						return
					}
					startAddr := frame.StartAddr
					data, err := CreateFrameRawData(list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
						return
					}
					if len(data) != frame.Quantity*2 {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]写入的寄存器个数与原始数据字节数不符;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
						return
					}
					err = client.WriteBytes(startAddr, data)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteBytes error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
						return
					}
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x10写入寄存器成功", ppe.Name, frame.Name)})

					frame.LastTriggerTime = time.Now()
				} else {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧不满足条件, 跳过", frame.Name, frame.ID)})
				}
				time.Sleep(1000 * time.Millisecond)
			}
		}
	}
}
func modbus0x05(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x05 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x05线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			if frame.SendType == 1 {
				list := make([]*FrameItemParam, 0)
				err := json.Unmarshal([]byte(frame.JsonDetail), &list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
					return
				}
				if frame.Quantity != 1 || len(list) != 1 {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]0x05写入单线圈个数必须为1; len=%d ,quantity=%d", ppe.Name, frame.Name, len(list), frame.Quantity)})
					return
				}
				err = client.SetUnitId(frame.SlaveID)
				if err != nil {
					j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
					return
				}
				startAddr := frame.StartAddr
				data, err := CreateFrameCoilsRawData(list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
					return
				}
				err = client.WriteCoil(startAddr, data[0])
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteCoil error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
					return
				}
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x05写入线圈成功", ppe.Name, frame.Name)})
				time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
			} else {
				match, err := IsTriggerConditionMatched(frame)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s] frame_id=%d, IsTriggerConditionMatched error %s", frame.Name, frame.ID, err.Error())})
					return
				}

				if match {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧满足条件", frame.Name, frame.ID)})
					if time.Now().Sub(frame.LastTriggerTime).Seconds() < float64(frame.TriggerInterval) {
						j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧距离下一次触发时间间隔未到, 跳过", frame.Name, frame.ID)})
						time.Sleep(1000 * time.Millisecond)
						continue
					}

					list := make([]*FrameItemParam, 0)
					err := json.Unmarshal([]byte(frame.JsonDetail), &list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
						return
					}
					if frame.Quantity != 1 || len(list) != 1 {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]0x05写入单线圈个数必须为1; len=%d ,quantity=%d", ppe.Name, frame.Name, len(list), frame.Quantity)})
						return
					}
					err = client.SetUnitId(frame.SlaveID)
					if err != nil {
						j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
						return
					}
					startAddr := frame.StartAddr
					data, err := CreateFrameCoilsRawData(list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
						return
					}
					err = client.WriteCoil(startAddr, data[0])
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteCoil error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
						return
					}
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x05写入线圈成功", ppe.Name, frame.Name)})

					frame.LastTriggerTime = time.Now()
				} else {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧不满足条件, 跳过", frame.Name, frame.ID)})
				}
				time.Sleep(1000 * time.Millisecond)
			}
		}
	}
}
func modbus0x06(ctx context.Context, ppe *PPE, client *modbus.ModbusClient, frame *Frame, stopChan chan int) {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"modbus0x06 panic", err})
			fmt.Println(string(debug.Stack()))
		}
		j_log.LogInfo([]interface{}{fmt.Sprintf("modbus0x06线程已退出 Frame:%d", frame.ID)})
		stopChan <- frame.ID
	}()
	for {
		select {
		case <-ctx.Done(): // 监听取消信号
			return
		default:
			if frame.SendType == 1 {
				list := make([]*FrameItemParam, 0)
				err := json.Unmarshal([]byte(frame.JsonDetail), &list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
					return
				}
				err = client.SetUnitId(frame.SlaveID)
				if err != nil {
					j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
					return
				}
				startAddr := frame.StartAddr
				data, err := CreateFrameRawData(list)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
					return
				}
				if len(data) != frame.Quantity*2 {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]写入的寄存器个数与原始数据字节数不符;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
					return
				}
				if len(data) != 2 {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]0x06写入单个寄存器时字节数必须为2;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
					return
				}
				err = client.WriteRegister(startAddr, tools.BytesToUint16(data, "big"))
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteRegister error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
					return
				}
				j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x06写入单个寄存器成功", ppe.Name, frame.Name)})
				time.Sleep(time.Duration(frame.ScanRate) * time.Millisecond)
			} else {
				match, err := IsTriggerConditionMatched(frame)
				if err != nil {
					j_log.LogError([]interface{}{fmt.Sprintf("[%s] frame_id=%d, IsTriggerConditionMatched error %s", frame.Name, frame.ID, err.Error())})
					return
				}
				if match {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧满足条件", frame.Name, frame.ID)})
					if time.Now().Sub(frame.LastTriggerTime).Seconds() < float64(frame.TriggerInterval) {
						j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧距离下一次触发时间间隔未到, 跳过", frame.Name, frame.ID)})
						time.Sleep(1000 * time.Millisecond)
						continue
					}

					list := make([]*FrameItemParam, 0)
					err := json.Unmarshal([]byte(frame.JsonDetail), &list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s] json解析失败 %v", ppe.Name, frame.Name, err.Error())})
						return
					}
					err = client.SetUnitId(frame.SlaveID)
					if err != nil {
						j_log.LogError([]interface{}{"设置从站地址失败:" + err.Error()})
						return
					}
					startAddr := frame.StartAddr
					data, err := CreateFrameRawData(list)
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]生成帧原始数据失败; %s", ppe.Name, frame.Name, err.Error())})
						return
					}
					if len(data) != frame.Quantity*2 {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]写入的寄存器个数与原始数据字节数不符;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
						return
					}
					if len(data) != 2 {
						j_log.LogError([]interface{}{fmt.Sprintf("[%s][%s]0x06写入单个寄存器时字节数必须为2;len=%d ,quantity=%d", ppe.Name, frame.Name, len(data), frame.Quantity)})
						return
					}
					err = client.WriteRegister(startAddr, tools.BytesToUint16(data, "big"))
					if err != nil {
						j_log.LogError([]interface{}{fmt.Sprintf("【%s】 WriteRegister error %s; data=%v\n", tools.GetNow(), err.Error(), data)})
						return
					}
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s] 0x06写入单个寄存器成功", ppe.Name, frame.Name)})

					frame.LastTriggerTime = time.Now()
				} else {
					j_log.LogInfo([]interface{}{fmt.Sprintf("[%s] frame_id=%d, 事件触发帧不满足条件, 跳过", frame.Name, frame.ID)})
				}
				time.Sleep(1000 * time.Millisecond)
			}
		}
	}
}

func (ppe *PPE) RunModbusTCPClient() {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"RunModbusTCPClient panic", err})
			fmt.Println(string(debug.Stack()))
		}

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4 // 设备停止
			_ = ppe.UpdateRunningState(4, "已停止")
			ppe.UnRegister()
			return
		}

		j_log.LogInfo([]interface{}{fmt.Sprintf("%s", ppe.Name), "3秒后重连"})
		ppe.RunningState = 0 // 设备异常
		ppe.Detail = "正在尝试重连..."
		_ = ppe.UpdateRunningState(5, "正在尝试重连...")
		time.Sleep(3 * time.Second)

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4 // 设备停止
			_ = ppe.UpdateRunningState(4, "已停止")
			ppe.UnRegister()
			return
		}

		ppe.RunModbusTCPClient()
	}()
	ppe.Register()
	config := ModbusTCPConfig{}
	err := json.Unmarshal([]byte(ppe.Config), &config)
	if err != nil {
		j_log.LogError([]interface{}{fmt.Sprintf("%s", ppe.Name), "ModbusTCPConfig json解析失败:" + err.Error()})
		return
	}

	url := fmt.Sprintf("tcp://%s:%d", config.IP, config.Port)
	client, err := modbus.NewClient(&modbus.ClientConfiguration{
		URL:     url,
		Timeout: 1 * time.Second,
	})
	if err != nil {
		j_log.LogError([]interface{}{url, "modbus.NewClient error:" + err.Error()})
		ppe.Detail = fmt.Sprintf("%v %v modbus.NewClient error: %v", ppe.Name, url, err.Error())
		return
	}
	err = client.Open()
	if err != nil {
		j_log.LogError([]interface{}{url, "modbus client.Open error:" + err.Error()})
		ppe.Detail = fmt.Sprintf("%v %v modbus client.Open error: %v", ppe.Name, url, err.Error())
		return
	}
	defer client.Close()
	ppe.RunningState = 2
	ppe.ModbusTCPClient = client
	j_log.LogInfo([]interface{}{fmt.Sprintf("【已启动】%s:%s", ppe.ProtocolName, ppe.Name)})
	ppe.Detail = "已启动"
	_ = ppe.UpdateRunningState(2, "已启动")

	ctxModbus, cancel := context.WithCancel(context.Background())
	defer cancel()

	stopChan := make(chan int, 1000)
	for _, frame := range ppe.FrameList {
		if frame.Status != 1 {
			continue
		}
		switch frame.FunctionCode {
		case "01":
			go modbus0x01(ctxModbus, ppe, client, frame, stopChan)
		case "02":
			go modbus0x02(ctxModbus, ppe, client, frame, stopChan)
		case "03":
			go modbus0x03(ctxModbus, ppe, client, frame, stopChan)
		case "04":
			go modbus0x04(ctxModbus, ppe, client, frame, stopChan)
		case "05":
			if frame.SendType >= 1 && frame.SendType <= 2 {
				go modbus0x05(ctxModbus, ppe, client, frame, stopChan)
			}
		case "06":
			if frame.SendType >= 1 && frame.SendType <= 2 {
				go modbus0x06(ctxModbus, ppe, client, frame, stopChan)
			}
		case "0F":
			if frame.SendType >= 1 && frame.SendType <= 2 {
				go modbus0x0F(ctxModbus, ppe, client, frame, stopChan)
			}
		case "10":
			if frame.SendType >= 1 && frame.SendType <= 2 {
				go modbus0x10(ctxModbus, ppe, client, frame, stopChan)
			}
		default:
			j_log.LogInfo([]interface{}{fmt.Sprintf("[%s][%s][%s] 无效的功能码", ppe.Name, frame.Name, frame.FunctionCode)})
			continue
		}
		time.Sleep(100 * time.Millisecond)
	}
	for {
		select {
		case frameID := <-stopChan:
			j_log.LogInfo([]interface{}{fmt.Sprintf("%s:frame_id=%d", ppe.Name, frameID), "子协程发送停止信号"})
			return
		default:
			if ppe.RunningState == 3 {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
	}
}

/*--- 下面为 Modbus Server ---*/

type SlaveDB struct {
	SlaveID          uint8
	CoilStatus       [65536]bool   // 01
	InputStatus      [65536]bool   // 02
	HoldingRegisters [65536]uint16 // 03
	InputRegister    [65536]uint16 // 04
}

type ModbusHandler struct {
	MaxQuantity uint16
	lock        sync.RWMutex
	uptime      uint32
	DB          map[uint8]*SlaveDB
	PPE         *PPE
}

func (ppe *PPE) RunModbusTCPServer() {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"RunModbusTCPServer panic", err})
			fmt.Println(string(debug.Stack()))
		}

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4 // 设备停止
			_ = ppe.UpdateRunningState(4, "已停止")
			ppe.UnRegister()
			return
		}

		j_log.LogInfo([]interface{}{fmt.Sprintf("%s", ppe.Name), "3秒后重启"})
		ppe.RunningState = 0 // 设备异常
		ppe.Detail = "正在尝试重启..."
		_ = ppe.UpdateRunningState(5, "正在尝试重启...")
		time.Sleep(3 * time.Second)

		if ppe.RunningState == 3 {
			j_log.LogInfo([]interface{}{"【已停止】", ppe.ProtocolName, ppe.Name})
			ppe.RunningState = 4 // 设备停止
			_ = ppe.UpdateRunningState(4, "已停止")
			ppe.UnRegister()
			return
		}
		ppe.RunModbusTCPServer()
	}()
	ppe.Register()
	config := ModbusTCPConfig{}
	err := json.Unmarshal([]byte(ppe.Config), &config)
	if err != nil {
		j_log.LogError([]interface{}{fmt.Sprintf("%s", ppe.Name), "ModbusTCPConfig json解析失败:" + err.Error()})
		return
	}

	mh := &ModbusHandler{}
	mh.DB = make(map[uint8]*SlaveDB)
	for _, db := range ppe.ModbusServerDB {
		mh.DB[db.SlaveID] = &SlaveDB{
			SlaveID: db.SlaveID,
		}
	}
	mh.MaxQuantity = uint16(config.MaxRequestQuantity)
	mh.PPE = ppe
	ppe.ModbusServerHandler = mh

	url := fmt.Sprintf("tcp://%s:%d", config.IP, config.Port)
	server, err := modbus.NewServer(&modbus.ServerConfiguration{
		URL:        url,                     // 监听地址
		Timeout:    30 * time.Second,        // 30秒无交互的连接自动关闭
		MaxClients: uint(config.MaxClients), // 最大客户端连接数
	}, mh)
	if err != nil {
		j_log.LogError([]interface{}{fmt.Sprintf("%s", ppe.Name), "modbus NewServer 失败:" + err.Error()})
		return
	}

	err = server.Start()
	if err != nil {
		j_log.LogError([]interface{}{fmt.Sprintf("%s", ppe.Name), "modbus server.Start 失败:" + err.Error()})
		return
	}
	defer server.Stop()
	j_log.LogInfo([]interface{}{fmt.Sprintf("【已启动】%s:%s", ppe.ProtocolName, ppe.Name)})
	ppe.Detail = "已启动"
	_ = ppe.UpdateRunningState(2, "已启动")
	stopChan := make(chan int, 1000)
	for {
		select {
		case frameID := <-stopChan:
			j_log.LogInfo([]interface{}{fmt.Sprintf("%s:frame_id=%d", ppe.Name, frameID), "子协程发送停止信号"})
			return
		default:
			if ppe.RunningState == 3 {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
	}
}

func (mh *ModbusHandler) SlaveIDExists(slaveID uint8) (db *SlaveDB, ok bool) {
	db, ok = mh.DB[slaveID]
	return
}

func (mh *ModbusHandler) HandleCoils(req *modbus.CoilsRequest) (res []bool, err error) {
	mh.lock.Lock()
	defer mh.lock.Unlock()
	db, ok := mh.SlaveIDExists(req.UnitId)
	if !ok {
		fmt.Printf("SlaveID 不存在\n")
		err = modbus.ErrIllegalFunction
		return
	}
	if req.Quantity == 0 {
		err = modbus.ErrIllegalDataAddress
		return
	}
	if req.Quantity > mh.MaxQuantity {
		fmt.Printf("每次最多读写%d个线圈\n", mh.MaxQuantity)
		err = modbus.ErrIllegalDataAddress
		return
	}

	var regAddr uint16
	if req.IsWrite { // 写
		for i := 0; i < int(req.Quantity); i++ {
			regAddr = req.Addr + uint16(i)
			db.CoilStatus[int(regAddr)] = req.Args[i]
		}
		err = mh.PPE.WriteModbusPointToVariables(req.UnitId)
		if err != nil {
			j_log.LogError([]interface{}{"modbus server更新变量值失败", err.Error()})
		}
	} else { // 读
		for i := 0; i < int(req.Quantity); i++ {
			regAddr = req.Addr + uint16(i)
			res = append(res, db.CoilStatus[int(regAddr)])
		}
	}
	return
}

func (mh *ModbusHandler) HandleDiscreteInputs(req *modbus.DiscreteInputsRequest) (res []bool, err error) {
	mh.lock.Lock()
	defer mh.lock.Unlock()
	db, ok := mh.SlaveIDExists(req.UnitId)
	if !ok {
		fmt.Printf("SlaveID 不存在\n")
		err = modbus.ErrIllegalFunction
		return
	}

	if req.Quantity == 0 {
		err = modbus.ErrIllegalDataAddress
		return
	}
	if req.Quantity > mh.MaxQuantity {
		fmt.Printf("每次最多读%d个线圈\n", mh.MaxQuantity)
		err = modbus.ErrIllegalDataAddress
		return
	}

	var regAddr uint16
	for i := 0; i < int(req.Quantity); i++ {
		regAddr = req.Addr + uint16(i)
		res = append(res, db.InputStatus[int(regAddr)])
	}
	return
}

func (mh *ModbusHandler) HandleHoldingRegisters(req *modbus.HoldingRegistersRequest) (res []uint16, err error) {
	mh.lock.Lock()
	defer mh.lock.Unlock()
	db, ok := mh.SlaveIDExists(req.UnitId)
	if !ok {
		fmt.Printf("SlaveID 不存在, len(mh.DB)=%d\n", len(mh.DB))
		err = modbus.ErrIllegalFunction
		return
	}
	if req.Quantity == 0 {
		err = modbus.ErrIllegalDataAddress
		return
	}
	if req.Quantity > mh.MaxQuantity {
		fmt.Printf("每次最多读写%d个寄存器\n", mh.MaxQuantity)
		err = modbus.ErrIllegalDataAddress
		return
	}
	var regAddr uint16
	if req.IsWrite { // 写
		for i := 0; i < int(req.Quantity); i++ {
			regAddr = req.Addr + uint16(i)
			db.HoldingRegisters[int(regAddr)] = req.Args[i]
		}
		err = mh.PPE.WriteModbusPointToVariables(req.UnitId)
		if err != nil {
			j_log.LogError([]interface{}{"modbus server更新变量值失败", err.Error()})
		}
	} else { // 读
		for i := 0; i < int(req.Quantity); i++ {
			regAddr = req.Addr + uint16(i)
			res = append(res, db.HoldingRegisters[int(regAddr)])
		}
	}
	return
}

func (mh *ModbusHandler) HandleInputRegisters(req *modbus.InputRegistersRequest) (res []uint16, err error) {
	mh.lock.RLock()
	defer mh.lock.RUnlock()
	db, ok := mh.SlaveIDExists(req.UnitId)
	if !ok {
		fmt.Printf("SlaveID 不存在\n")
		err = modbus.ErrIllegalFunction
		return
	}
	if req.Quantity == 0 {
		err = modbus.ErrIllegalDataAddress
		return
	}
	if req.Quantity > mh.MaxQuantity {
		fmt.Printf("每次最多读%d个寄存器\n", mh.MaxQuantity)
		err = modbus.ErrIllegalDataAddress
		return
	}

	var regAddr uint16
	for i := 0; i < int(req.Quantity); i++ {
		regAddr = req.Addr + uint16(i)
		res = append(res, db.InputRegister[int(regAddr)])
	}
	return
}

/*

Modbus功能码及作用说明
01:读线圈			对可读写型的状态量进行读取
02:读离散量输入		对只读型的状态量进行读取
03:读保持寄存器		对可读写型的寄存器量进行读取
04:读输入寄存器		对只读型的寄存器量进行读取
05:写单个线圈			对单个的读写型的状态量进行写入
06:写单个寄存器		对单个的读写型的寄存器量进行写入
0F:写多个线圈			对多个的读写型的状态量进行写入
10:写多个寄存器		对多个的读写型的寄存器量进行写入

*/
